<!DOCTYPE html>
<html>
<head>
<title>Mass-Spring System</title>
</head>
<body>
<canvas id="physicsCanvas" width="600" height="400"></canvas>
<script>
    const canvas = document.getElementById('physicsCanvas');
    const ctx = canvas.getContext('2d');

    // Style settings
    ctx.strokeStyle = 'black';
    ctx.fillStyle = 'black';
    ctx.lineWidth = 1;
    ctx.font = '16px sans-serif';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'middle';

    // --- Fixed Support ---
    // Horizontal bar
    ctx.lineWidth = 2;
    ctx.beginPath();
    ctx.moveTo(180, 50);
    ctx.lineTo(420, 50);
    ctx.stroke();

    // Hatching
    ctx.lineWidth = 1;
    for (let x = 195; x < 420; x += 20) {
        ctx.beginPath();
        ctx.moveTo(x, 50);
        ctx.lineTo(x - 15, 35);
        ctx.stroke();
    }

    // Attachment point
    ctx.beginPath();
    ctx.arc(300, 50, 5, 0, 2 * Math.PI);
    ctx.fill();

    // --- Spring ---
    ctx.lineWidth = 1.5;
    const cx = 300;
    const y_start = 55;
    const length = 145;
    const coils = 8;
    const radius = 40;
    
    ctx.beginPath();
    ctx.moveTo(cx, 50);
    ctx.lineTo(cx, y_start);

    const segment_len = length / (coils * 2);
    let y = y_start;
    let sign = -1;
    for (let i = 0; i < coils * 2; i++) {
        ctx.quadraticCurveTo(cx + sign * radius, y + segment_len / 2, cx, y + segment_len);
        y += segment_len;
        sign *= -1;
    }
    
    const spring_end_y = y;
    ctx.lineTo(cx, spring_end_y + 5);
    ctx.stroke();


    // --- Object ---
    const obj_attach_y = spring_end_y + 5;
    // Attachment circle on object
    ctx.lineWidth = 1;
    ctx.beginPath();
    ctx.arc(cx, obj_attach_y, 4, 0, 2 * Math.PI);
    ctx.fillStyle = 'white';
    ctx.fill();
    ctx.stroke();
    
    // Trapezoid body
    ctx.fillStyle = 'black'; // Reset for other fills
    const obj_top_y = obj_attach_y + 4;
    const obj_height = 50;
    ctx.beginPath();
    ctx.moveTo(cx - 30, obj_top_y); // top left
    ctx.lineTo(cx + 30, obj_top_y); // top right
    ctx.lineTo(cx + 45, obj_top_y + obj_height); // bottom right
    ctx.lineTo(cx - 45, obj_top_y + obj_height); // bottom left
    ctx.closePath();
    ctx.stroke();


    // --- Equilibrium Position ---
    const eq_y = obj_top_y + obj_height / 2;
    ctx.beginPath();
    ctx.setLineDash([5, 5]);
    ctx.moveTo(180, eq_y);
    ctx.lineTo(520, eq_y);
    ctx.stroke();
    ctx.setLineDash([]); // Reset line dash


    // --- Oscillations Arrow ---
    const arrow_x = 420;
    const arrow_top_y = 150;
    const arrow_bottom_y = 320;
    ctx.lineWidth = 1.5;
    // Line
    ctx.beginPath();
    ctx.moveTo(arrow_x, arrow_top_y);
    ctx.lineTo(arrow_x, arrow_bottom_y);
    ctx.stroke();
    // Top arrowhead
    ctx.beginPath();
    ctx.moveTo(arrow_x, arrow_top_y);
    ctx.lineTo(arrow_x - 4, arrow_top_y + 8);
    ctx.moveTo(arrow_x, arrow_top_y);
    ctx.lineTo(arrow_x + 4, arrow_top_y + 8);
    ctx.stroke();
    // Bottom arrowhead
    ctx.beginPath();
    ctx.moveTo(arrow_x, arrow_bottom_y);
    ctx.lineTo(arrow_x - 4, arrow_bottom_y - 8);
    ctx.moveTo(arrow_x, arrow_bottom_y);
    ctx.lineTo(arrow_x + 4, arrow_bottom_y - 8);
    ctx.stroke();


    // --- Labels ---
    ctx.lineWidth = 1;
    // 'fixed point'
    ctx.fillText('fixed point', 410, 45);
    ctx.beginPath();
    ctx.moveTo(405, 47);
    ctx.lineTo(310, 50);
    ctx.stroke();
    
    // 'spring'
    ctx.fillText('spring', 150, 140);
    ctx.beginPath();
    ctx.moveTo(200, 140);
    ctx.lineTo(260, 145);
    ctx.stroke();

    // 'object'
    ctx.fillText('object', 180, 220);
    ctx.beginPath();
    ctx.moveTo(228, 220);
    ctx.lineTo(265, 235);
    ctx.stroke();
    
    // 'oscillations'
    ctx.fillText('oscillations', 435, 210);

    // 'equilibrium position'
    ctx.fillText('equilibrium position', 435, eq_y);

    // --- Figure Caption ---
    ctx.textAlign = 'center';
    ctx.font = 'bold 16px sans-serif';
    ctx.fillText('Fig. 3.1', 300, 350);

</script>
</body>
</html>